/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.list.boost;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.*;
import cn.easyplatform.messages.response.ListPagingResponseMessage;
import cn.easyplatform.messages.vos.FieldUpdateVo;
import cn.easyplatform.messages.vos.datalist.*;
import cn.easyplatform.spi.service.ComponentService;
import cn.easyplatform.spi.service.ListService;
import cn.easyplatform.type.DeviceType;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.ext.zul.Datalist;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.task.event.EventEntry;
import cn.easyplatform.web.task.event.FieldEntry;
import cn.easyplatform.web.task.OperableHandler;
import cn.easyplatform.web.task.BackendException;
import cn.easyplatform.web.task.MainTaskSupport;
import cn.easyplatform.web.task.support.CellCreater;
import cn.easyplatform.web.task.support.ManagedComponent;
import cn.easyplatform.web.task.support.SupportFactory;
import cn.easyplatform.web.task.zkex.list.OperableListSupport;
import cn.easyplatform.web.task.zkex.list.exporter.AbstractExporter;
import cn.easyplatform.web.task.zkex.list.menu.ColumnMenu;
import cn.easyplatform.web.task.zkex.list.menu.SimpleColumnMenu;
import cn.easyplatform.web.utils.PageUtils;
import cn.easyplatform.web.utils.WebUtils;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlBasedComponent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.*;
import org.zkoss.zul.event.ZulEvents;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Author: <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @Description:
 * @Since: 2.0.0 <br/>
 * @Date: Created in 2019/7/30 18:33
 * @Modified By:
 */
public class HierarchyBoostBuilder extends AbstractBoostBuilder implements OperableHandler {

    private String processCode;

    public HierarchyBoostBuilder(OperableHandler mainTaskHandler, Datalist entity, Component anchor) {
        super(mainTaskHandler, entity, anchor);
    }

    @Override
    protected Component createContent() {
        getEntity().setShowRowNumbers(false);
        listExt.appendChild(new Rows());
        Component container = super.createContent();
        if (getEntity().getPageSize() > 0) {
            if (getEntity().isFetchAll()) {
                listExt.setMold("paging");
                listExt.setPageSize(getEntity().getPageSize());
                listExt.getPaginal().setPageSize(listExt.getPageSize());
                paging = listExt.getPagingChild();
                paging.setAutohide(getEntity().isPagingAutohide());
                paging.setDetailed(getEntity().isPagingDetailed());
                if (getEntity().getPagingMold() != null)
                    paging.setMold(getEntity().getPagingMold());
                if (getEntity().getPagingStyle() != null)
                    paging.setStyle(getEntity().getPagingStyle());
            } else {
                South south = new South();
                south.setHflex("1");
                //south.setVflex("1");
                south.setBorder("none");
                paging = new Paging();
                if (layout.getData() == null || layout.getData().isEmpty())
                    paging.setTotalSize(layout.getTotalSize());
                else
                    paging.setTotalSize(layout.getTotalSize());
                paging.setPageSize(getEntity().getPageSize());
                paging.setDetailed(getEntity().isPagingDetailed());
                paging.setAutohide(getEntity().isPagingAutohide());
                if (layout instanceof ListRecurVo) {
                    int activePage = ((ListRecurVo) layout).getStartPageNo();
                    if (activePage > 0)
                        paging.setActivePage(activePage - 1);
                }
                if (!getEntity().isFetchAll())
                    paging.addEventListener(ZulEvents.ON_PAGING, this);
                paging.setHflex("1");
                paging.setVflex("1");
                south.appendChild(paging);
                container.appendChild(south);
            }
        }
        return container;
    }

    @Override
    protected void createHeader() {
        if (!Strings.isBlank(layout.getOnRow()))
            expressionEngine = SupportFactory.getExpressionEngine(this,
                    layout.getOnRow());
        super.createHeader();
    }

    @Override
    protected void redraw(List<ListRowVo> rowset) {
        if (rowset == null || rowset.isEmpty())
            return;
        try {
            if (expressionEngine != null)
                expressionEngine.compile();
            Map<String, Object> evalMap = new HashMap<String, Object>();
            Map<String, Component> managedComponents = new HashMap<String, Component>();
            for (ListRowVo rv : rowset) {
                evalMap.clear();
                managedComponents.clear();
                listIndex++;
                Row row = createRow(rv, evalMap, managedComponents);
                if (expressionEngine != null)
                    expressionEngine.eval(row, evalMap, managedComponents);
            }
        } finally {
            if (expressionEngine != null)
                expressionEngine.destroy();
        }
    }

    private Row createRow(ListRowVo rv, Map<String, Object> evalMap,
                          Map<String, Component> managedComponents) {
        Row row = new Row();
        if (!Strings.isBlank(rowStyle))
            row.setStyle(rowStyle);
        Object[] data = rv.getData();
        row.setParent(listExt.getRows());
        row.setValue(rv);
        CellCreater creater = SupportFactory.getCellCreater(this);
        for (int i = 0; i < data.length; i++) {
            ListHeaderVo hv = layout.getHeaders().get(i);
            evalMap.put(hv.getName(), data[i]);
            if (hv.isTotal() && data[i] != null)
                hv.caculate(data[i].toString());
            Component c = creater.createCell(row, managedComponents, hv, rv, i);
            if (c instanceof Detail) {//detail
                //listExt.getRows().appendChild(c);
                row.appendChild(c);
            } else {
                if (c.getFirstChild() == null)
                    managedComponents.put(hv.getName(), c);
                else
                    managedComponents.put(hv.getName(), c.getFirstChild());
                row.appendChild(c);
            }
        }
        if (clickType > 0) {//增加事件处理
            row.setEvent(listExt.getEvent());
            addEventListener(row, clickType == 1 ? Events.ON_CLICK
                    : Events.ON_DOUBLE_CLICK);
        }
        if (getEntity().getDepth() == 1) {
            if (listExt.getRows().getChildren().size() == 1) {
                Component c = row.getFirstChild();
                if (c instanceof Detail)
                    ((Detail) c).setOpen(true);
            }
        } else if (getEntity().getDepth() > 1) {
            Component c = row.getFirstChild();
            if (c instanceof Detail)
                ((Detail) c).setOpen(true);
        }
        managedComponents.put("self", row);
        return row;
    }

    @Override
    public void paging(int pageNo) {
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        ListPagingRequestMessage req = new ListPagingRequestMessage(getId(),
                new ListPagingVo(listExt.getId(), pageNo));
        IResponseMessage<?> resp = dls.doPaging(req);
        if (!resp.isSuccess()) {
            MessageBox.showMessage(resp.getCode(), (String) resp.getBody());
        } else {
            List<ListRowVo> data = ((ListPagingResponseMessage) resp).getBody();
            clear();
            listIndex = (pageNo - 1) * getEntity().getPageSize();
            redraw(data);
        }
    }

    @Override
    protected void setPagingInfo(int totalSize, int activePageNo) {
        if (paging != null) {
            if (totalSize >= 0)
                paging.setTotalSize(totalSize);
            paging.setActivePage(activePageNo);
        }
    }

    @Override
    protected void setMenupopup(HtmlBasedComponent head) {
        if (Contexts.getEnv().getDeviceType().equalsIgnoreCase(DeviceType.AJAX.getName())) {
            Component layout = listExt.getParent().getParent();
            West west = new West();
            west.setBorder("none");
            west.setSize("0");
            west.setCollapsible(false);
            layout.appendChild(west);
            Menupopup popup = new SimpleColumnMenu(head, this, getEntity().isExport(),
                    getEntity().isPrint());
            popup.setId(listExt.getId() + "_popup");
            west.appendChild(popup);
            ((Columns) head).setMenupopup(popup.getId());
        }
    }

    @Override
    public void setPageSize(int pageSize) {
        getEntity().setPageSize(pageSize);
        paging.setPageSize(pageSize);
        paging.setActivePage(0);
    }

    @Override
    public void onEvent(Event event) throws Exception {
        try {
            if (event.getTarget() instanceof Menuitem) {
                String id = (String) event.getTarget().getAttribute("id");
                id = id == null ? "" : id;
                if (id.equals("--exp--")) {
                    AbstractExporter.createExporter(mainTaskHandler, this)
                            .doExport();
                } else if (id.equals("--filter--")) {
                    ColumnMenu menu = (ColumnMenu) event.getTarget()
                            .getParent();
                    filter(menu.getHeader());
                }
            } else super.onEvent(event);
        } catch (EasyPlatformWithLabelKeyException ex) {
            MessageBox.showMessage(ex);
        } catch (BackendException ex) {
            MessageBox.showMessage(ex.getMsg().getCode(), (String) ex.getMsg()
                    .getBody());
        }
    }


    @Override
    public OperableHandler getMainHandler() {
        return this;
    }

    @Override
    public void refresh(EventEntry<FieldEntry> entry) {

    }

    @Override
    public void update(String... comps) {
        if (log.isDebugEnabled())
            log.debug("update->{}", Lang.concat(comps));
        if (comps.length == 0)
            return;
        ListRowVo rv = getSelectedValue();
        ListFieldUpdateVo lfus = new ListFieldUpdateVo(listExt.getId(),
                isCustom() ? rv.getData() : rv.getKeys());
        Set<Map.Entry<String, Component>> set = getManagedComponents().entrySet();
        for (Map.Entry<String, Component> entry : set) {
            Component comp = entry.getValue();
            if (comps[0].equals("*")) {
                lfus.addField(new FieldUpdateVo(entry.getKey(), PageUtils
                        .getValue(comp, false)));
            } else {
                for (int i = 0; i < comps.length; i++) {
                    if (entry.getKey().equals(comps[i])) {
                        lfus.addField(new FieldUpdateVo(comps[i], PageUtils
                                .getValue(comp, false)));
                        break;
                    }
                }
            }
        }
        SimpleRequestMessage req = new SimpleRequestMessage(getId(), lfus);
        IResponseMessage<?> resp = ServiceLocator.lookup(
                ComponentService.class).fieldUpdate(req);
        if (!resp.isSuccess())
            throw new BackendException(resp);
    }

    @Override
    public String getTaskId() {
        return mainTaskHandler.getTaskId();
    }

    @Override
    public String getProcessCode() {
        return processCode;
    }

    @Override
    public void setProcessCode(String code) {
        this.processCode = code;
    }

    @Override
    public Component getContainer() {
        return mainTaskHandler.getContainer();
    }

    public boolean isEditable() {
        return !Strings.isBlank(getEntity().getEditableColumns());
    }

    private Object[] getFromKeys() {
        Object[] keys = null;
        for (ManagedComponent es : ((MainTaskSupport) getParent())
                .getManagedEntityComponents()) {
            if (es instanceof OperableListSupport) {
                OperableHandler os = (OperableHandler) es;
                if (os.getComponent().getId().equals(getEntity().getHost())) {
                    if (os.getComponent() instanceof Listbox) {
                        Listbox dl = (Listbox) os.getComponent();
                        if (dl.getSelectedCount() == 0)
                            throw new EasyPlatformWithLabelKeyException(
                                    "datalist.from.selected.empty", getName());
                        keys = ((ListRowVo) dl.getSelectedItem().getValue())
                                .getKeys();
                        break;
                    } else if (os.getComponent() instanceof Tree) {
                        Tree dl = (Tree) os.getComponent();
                        if (dl.getSelectedCount() == 0)
                            throw new EasyPlatformWithLabelKeyException(
                                    "datalist.from.selected.empty", getName());
                        keys = ((ListRowVo) dl.getSelectedItem().getValue())
                                .getKeys();
                        break;
                    } else {
                        Grid grid = (Grid) os.getComponent();
                        Row row = (Row) grid.getAttribute("selectRow");
                        if (row == null)
                            throw new EasyPlatformWithLabelKeyException(
                                    "datalist.from.selected.empty", getName());
                        ListRowVo rv = row.getValue();
                        keys = rv.getKeys();
                        break;
                    }
                }
            }
        }
        if (keys == null)
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.from.not.found", getEntity().getHost());
        return keys;
    }

    protected void open(String code, ListRowVo rv) {
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        ListSelectedRowVo srv = new ListSelectedRowVo(listExt.getId(),
                rv == null ? null : rv.getKeys());
        srv.setCode(code);
        IResponseMessage<?> resp = dls
                .doSelect(new ListSelectRequestMessage(mainTaskHandler
                        .getId(), srv));
        if (!resp.isSuccess())
            throw new BackendException(resp);
        mainTaskHandler.setProcessCode(code);
        mainTaskHandler.reload(new String[0]);
    }

    private void createRow(ListRowVo rv) {
        try {
            if (expressionEngine != null)
                expressionEngine.compile();
            Map<String, Object> evalMap = new HashMap<String, Object>();
            Map<String, Component> managedComponents = new HashMap<String, Component>();
            createRow(rv, evalMap, managedComponents);
        } finally {
            if (expressionEngine != null)
                expressionEngine.destroy();
        }
    }

    @Override
    public void create(EventEntry<String> entry) {
        if (isCustom())
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.invalid.action", getName());
        processCode = "C";
        if (isEditable()) {
            ListService dls = ServiceLocator
                    .lookup(ListService.class);
            ListCreateVo cv = new ListCreateVo(listExt.getId());
            if (!Strings.isBlank(getEntity().getHost()))
                cv.setFromKeys(getFromKeys());
            IResponseMessage<?> resp = dls
                    .doCreate(new ListCreateRequestMessage(getId(), cv));
            if (resp.isSuccess()) {
                createRow((ListRowVo) resp.getBody());
            } else
                throw new BackendException(resp);
        } else
            open("C", null);
    }

    @Override
    public void copy(EventEntry<String> entry) {
        ListRowVo rv = getSelectedValue();
        if (rv == null)
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.selected.empty", getName());
        processCode = "C";
        if (isEditable()) {
            ListService dls = ServiceLocator
                    .lookup(ListService.class);
            ListCreateVo cv = new ListCreateVo(listExt.getId());
            if (!Strings.isBlank(getEntity().getHost()))
                cv.setFromKeys(getFromKeys());
            cv.setCopyKeys(rv.getKeys());
            IResponseMessage<?> resp = dls
                    .doCreate(new ListCreateRequestMessage(getId(), cv));
            if (resp.isSuccess())
                createRow((ListRowVo) resp.getBody());
            else
                throw new BackendException(resp);
        } else
            open("C", rv);
    }

    @Override
    public void delete(EventEntry<String> entry) {
        if (isCustom())
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.invalid.action", getName());
        ListRowVo rv = getSelectedValue();
        if (rv == null)
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.selected.empty", getName());
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        ListSelectetRowsVo srv = new ListSelectetRowsVo(listExt.getId());
        srv.appendKey(rv.getKeys());
        IResponseMessage<?> resp = dls.doDelete(new ListDeleteRequestMessage(
                getId(), srv));
        if (resp.isSuccess()) {
            Component c = (Component) listExt.getAttribute("selectRow");
            c.detach();
        } else
            throw new BackendException(resp);
    }

    @Override
    public void edit(EventEntry<String> entry) {
        if (isCustom())
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.invalid.action", getName());
        ListRowVo rv = getSelectedValue();
        if (rv == null)
            throw new EasyPlatformWithLabelKeyException(
                    "datalist.selected.empty", getName());
        processCode = "U";
        open("U", rv);
    }

    @Override
    public void save(EventEntry<Boolean> entry) {
        ListSaveVo sv = null;
        if (entry.getEntry()) {// commit提交列表
            sv = new ListSaveVo(listExt.getId());
        } else {// save提交所选的记录
            Row row = (Row) listExt.getAttribute("selectRow");
            if (row == null) {
                sv = new ListSaveVo(listExt.getId());
            } else {
                if (WebUtils.isCellEvent()) {
                    ListRowVo rv = WebUtils.getItemData(this, row);
                    sv = new ListSaveVo(listExt.getId(), rv.getKeys(), rv.getData());
                } else
                    sv = new ListSaveVo(listExt.getId());
            }
        }
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        IResponseMessage<?> resp = dls.doSave(new ListSaveRequestMessage(
                getId(), sv));
        if (!resp.isSuccess())
            throw new BackendException(resp);
    }

    @Override
    public String[] getAccess() {
        return mainTaskHandler.getAccess();
    }
}
